#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/12/11 20:14
# @Author  : 唐松
# @File    : yaml_extract.py
# @Software: PyCharm

import json
import re

import allure
import jsonpath
from configs.config import write_extract_yaml
from util_tools.logger_util import logs
from util_tools.other_util.allure_type import allure_attach_dict_result


class YamlExtract:
    # 定义一个类YamlExtract, 用于处理yaml数据中的'extract',提取接口参数

    def __init__(self):
        pass

    @classmethod
    def extract_data(cls, testcase_extract, response_text):
        """
        提取单个参数，提取接口的返回参数，支持正则表达式提取和json提取器
        :param testcase_extract: yaml文件中extract字段
        :param response_text: (str)接口实际返回结果
        :return:
        """
        extract_data = {}
        try:
            # 遍历提取配置中的每个键值对
            for extract_key, extract_value in testcase_extract.items():
                # 检查是否使用正则表达式
                if any(pat in extract_value for pat in ['(.*?)', '(.+?)', r'(\d+)', r'(\d*)']):
                    ext_list = re.search(extract_value, response_text)
                    # 使用正则表达式提取数据
                    if ext_list:
                        # 如何ext_list不为空，则将提取到的数据存储到extract_data中
                        value = int(ext_list.group(1)) if r'(\d+)' in extract_value else ext_list.group(1)
                        # 将提取到的数据存储到 extract_data 中
                        extract_data[extract_key] = value
                        # logs.info(f"单参数,正则提取数据:{extract_data}")
                    else:
                        # 如果ext_list为空，则抛出异常
                        logs.error("单参数,正则表达式未提取到数据,请检查yaml文件extract表达式是否正确！")

                # 检查是否使用JSON提取器
                elif "$" in extract_value:
                    # 使用jsonpath提取数据,jsonpath提取器
                    extract_json = jsonpath.jsonpath(json.loads(response_text), extract_value)
                    if extract_json:
                        # 将提取到的数据存储到 extract_data 中
                        extract_data[extract_key] = extract_json[0]
                        # logs.info(f"单参数,JSON提取数据: {extract_data}")
                    else:
                        # 如果提取失败，存储错误信息
                        logs.error("单参数,JSON未提取到数据, 请检查接口返回信息或表达式！")
                else:
                    # 如果无法识别的extract表达式，记录错误日志并返回 None
                    logs.error(f"无法识别的extract表达式：{extract_value}。请使用合法的正则或JSONPath表达式。")

            if extract_data:
                # 添加到 Allure报告
                allure.attach(allure_attach_dict_result(extract_data), name='提取数据(extract_data)',
                              attachment_type=allure.attachment_type.JSON)
                # 将提取的数据写入YAML文件
                logs.info(f"单参数extract,提取数据: {extract_data}")
                write_extract_yaml(extract_data)

        except re.error as e:
            logs.error(f'正则表达式解析错误:{e},请检查yaml文件extract表达式是否正确！')
        except json.JSONDecodeError as e:
            # 处理JSON解析错误，并记录错误日志
            logs.error(f'JSON解析错误:{e},请检查yaml文件extract表达式是否正确！')

    @classmethod
    def extract_data_list(cls, testcase_extract_list, response_text):
        """
        提取多个参数，提取接口的返回参数，支持正则表达式提取和json提取器
        :param testcase_extract_list: yaml文件中extract_list字段
        :param response_text: 接口返回结果
        :return:
        """

        extract_data = {}
        try:
            # 遍历测试用例提取列表中的每个键值对
            for extract_key, extract_value in testcase_extract_list.items():
                # 如果值中包含正则表达式模式，则进行正则提取
                if any(pat in extract_value for pat in ['(.*?)', '(.+?)', r'(\d+)', r'(\d*)']):
                    # 使用正则表达式在响应文本中查找匹配项
                    ext_list = re.findall(extract_value, response_text, re.S)
                    # 提取匹配的第一个组，并根据需要转换为整数
                    if ext_list:
                        extract_data[extract_key] = ext_list
                        # logs.info(f"多参数,正则提取数据:{extract_data}")
                    else:
                        logs.error("多参数,正则表达式未提取到数据,请检查yaml文件extract表达式是否正确！")
                # 如果值中包含"$"，则认为是jsonpath表达式
                elif "$" in extract_value:
                    # 使用jsonpath从响应文本中提取数据
                    extract_json = jsonpath.jsonpath(json.loads(response_text), extract_value)
                    # 如果提取成功，将结果存储在字典中，键为当前的key
                    if extract_json:
                        # 将提取到的数据存储到extract_data
                        extract_data[extract_key] = extract_json
                        # 记录提取到的数据日志
                        # logs.info(f"多参数,JSON提取数据:{extract_data}")
                    else:
                        # 如果提取失败，存储错误信息
                        logs.error("多参数,JSON未提取到数据,请检查接口返回信息或表达式！")
                else:
                    logs.error(f"无法识别的extract表达式：{extract_value}。请使用合法的正则或JSONPath表达式。")
            if extract_data:
                # 添加到 Allure报告
                allure.attach(allure_attach_dict_result(extract_data), name='提取数据(extract_data_list)',
                              attachment_type=allure.attachment_type.JSON)
                # 如果提取到了数据，将其写入到yaml文件中
                logs.info(f"多参数extract_list,提取数据: {extract_data}")
                write_extract_yaml(extract_data)
        except re.error:
            logs.error('正则表达式解析错误,请检查yaml文件extract表达式是否正确！')
        except json.JSONDecodeError:
            logs.error('JSON解析错误,请检查yaml文件extract表达式是否正确！')
